package king.dominic.jlibrary.util;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import king.dominic.jlibrary.BuildConfig;
import king.dominic.jlibrary.R;
import king.dominic.jlibrary.activity.OriginPermissionActivity;

/**
 * Created by king on 2017/2/19.
 * PermissionUtil
 */

public class PermissionUtil {
    public interface PermissionHandler {
        void add(PermissionItem item);

        Activity getActivity();

        void handlerRequestPermissions(@NonNull String[] permissions, int requestCode);
    }

    public static class PermissionItem {
        private final Runnable runnable;
        private final Activity activity;
        //        private final String[] permissions;
//        private final String[] names;
        private final HashMap<String, String> mPermissions = new HashMap<>();
        private int requestCode;

        private PermissionItem(Activity activity, String permission, String name, Runnable runnable, int requestCode) {
            this(activity, new String[]{permission}, new String[]{name}, runnable, requestCode);
        }

        private PermissionItem(Activity activity, String[] permissions, String[] names, Runnable runnable, int requestCode) {
            this.activity = activity;
            this.runnable = runnable;
            this.requestCode = requestCode;
            for (int i = 0; i < names.length; i++) {
                mPermissions.put(permissions[i], names[i]);
            }
        }
    }

    private static String getNames(String[] names) {
        if (names == null || names.length == 0) return "";
        StringBuilder builder = new StringBuilder();
        for (String n : names) {
            if (builder.toString().contains(n)) continue;
            builder.append(n);
            builder.append("、");
        }
        builder.delete(builder.length() - 1, builder.length());
        return builder.toString();
    }

    /**
     * 申请权限组
     *
     * @param handler         PermissionListener
     * @param permissionGroup 权限组
     * @param runnable        申请成功回调
     */
    public static void callGroup(PermissionHandler handler, String permissionGroup, Runnable runnable) {
        callMethod(handler, permissionChildren(permissionGroup), runnable);
    }

    public static void callGroup(OriginPermissionActivity activity, String permissionGroup, Runnable runnable) {
        callGroup((PermissionHandler) activity, permissionGroup, runnable);
    }

    public static void callMethod(PermissionHandler handler, String permission, Runnable runnable) {
        callMethod(handler, new String[]{permission}, runnable);
    }

    public static void callMethodNoCallback(PermissionHandler handler, String[] permissions, Runnable runnable) {
        callMethod(handler, permissions, true, runnable);
    }

    public static void callMethod(PermissionHandler handler, String[] permissions, Runnable runnable) {
        callMethod(handler, permissions, false, runnable);
    }

    public static void callMethod(OriginPermissionActivity activity, String[] permissions, Runnable runnable) {
        callMethod(activity, permissions, false, runnable);
    }

    /**
     * 申请权限
     *
     * @param handler     PermissionListener
     * @param permissions 权限
     * @param runnable    申请成功回调
     */
    private static void callMethod(PermissionHandler handler, String[] permissions, boolean noCallback, Runnable runnable) {
        Activity activity = handler.getActivity();
        if (activity == null) return;
        String[] name = new String[permissions.length];
        for (int i = 0; i < permissions.length; i++) {
            name[i] = permissionName(activity, permissions[i]);
        }
        if (permissions.length == 1)
            checkSelfPermission(handler, permissions[0], name[0], noCallback, runnable);
        else
            checkSelfPermissions(handler, permissions, name, noCallback, runnable);
    }

    private static void callMethod(OriginPermissionActivity activity, String[] permissions, boolean noCallback, Runnable runnable) {
        callMethod((PermissionHandler) activity, permissions, noCallback, runnable);
    }

    public static String permissionName(Context context, String permission) {
        return permissionGroupName(context, permissionGroup(permission));
    }

    public static String[] permissionChildren(String permissionGroup) {
        switch (permissionGroup) {
            case Manifest.permission_group.CONTACTS:
                return new String[]{
                        Manifest.permission.WRITE_CONTACTS,
                        Manifest.permission.GET_ACCOUNTS,
                        Manifest.permission.READ_CONTACTS};
            case Manifest.permission_group.PHONE:
                return new String[]{
                        Manifest.permission.READ_CALL_LOG,
                        Manifest.permission.READ_PHONE_STATE,
                        Manifest.permission.CALL_PHONE,
                        Manifest.permission.WRITE_CALL_LOG,
                        Manifest.permission.USE_SIP,
                        Manifest.permission.PROCESS_OUTGOING_CALLS,
                        Manifest.permission.ADD_VOICEMAIL,};
            case Manifest.permission_group.CALENDAR:
                return new String[]{
                        Manifest.permission.READ_CALENDAR,
                        Manifest.permission.WRITE_CALENDAR,};
            case Manifest.permission_group.CAMERA:
                return new String[]{
                        Manifest.permission.CAMERA,};
            case Manifest.permission_group.SENSORS:
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
                    return new String[]{
                            Manifest.permission.BODY_SENSORS,};
                }
            case Manifest.permission_group.LOCATION:
                return new String[]{
                        Manifest.permission.ACCESS_FINE_LOCATION,
                        Manifest.permission.ACCESS_COARSE_LOCATION,};
            case Manifest.permission_group.STORAGE:
                return new String[]{
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,};
            case Manifest.permission_group.MICROPHONE:
                return new String[]{
                        Manifest.permission.RECORD_AUDIO,};
            case Manifest.permission_group.SMS:
                return new String[]{
                        Manifest.permission.READ_SMS,
                        Manifest.permission.RECEIVE_WAP_PUSH,
                        Manifest.permission.RECEIVE_MMS,
                        Manifest.permission.RECEIVE_SMS,
                        Manifest.permission.SEND_SMS,
                        "android.permission.READ_CELL_BROADCASTS",};
        }
        return null;
    }

    @TargetApi(Build.VERSION_CODES.M)
    public static String permissionGroup(String permission) {
        switch (permission) {
            case Manifest.permission.WRITE_CONTACTS:
            case Manifest.permission.GET_ACCOUNTS:
            case Manifest.permission.READ_CONTACTS:
                return Manifest.permission_group.CONTACTS;
            case Manifest.permission.READ_CALL_LOG:
            case Manifest.permission.READ_PHONE_STATE:
            case Manifest.permission.CALL_PHONE:
            case Manifest.permission.WRITE_CALL_LOG:
            case Manifest.permission.USE_SIP:
            case Manifest.permission.PROCESS_OUTGOING_CALLS:
            case Manifest.permission.ADD_VOICEMAIL:
                return Manifest.permission_group.PHONE;
            case Manifest.permission.READ_CALENDAR:
            case Manifest.permission.WRITE_CALENDAR:
                return Manifest.permission_group.CALENDAR;
            case Manifest.permission.CAMERA:
                return Manifest.permission_group.CAMERA;
            case Manifest.permission.BODY_SENSORS:
                return Manifest.permission_group.SENSORS;
            case Manifest.permission.ACCESS_FINE_LOCATION:
            case Manifest.permission.ACCESS_COARSE_LOCATION:
                return Manifest.permission_group.LOCATION;
            case Manifest.permission.READ_EXTERNAL_STORAGE:
            case Manifest.permission.WRITE_EXTERNAL_STORAGE:
                return Manifest.permission_group.STORAGE;
            case Manifest.permission.RECORD_AUDIO:
                return Manifest.permission_group.MICROPHONE;
            case Manifest.permission.READ_SMS:
            case Manifest.permission.RECEIVE_WAP_PUSH:
            case Manifest.permission.RECEIVE_MMS:
            case Manifest.permission.RECEIVE_SMS:
            case Manifest.permission.SEND_SMS:
            case "android.permission.READ_CELL_BROADCASTS":
                return Manifest.permission_group.SMS;
        }
        return permission;
    }

    public static String permissionSingleName(Context context, String permission) {
        switch (permission) {
            case Manifest.permission.WRITE_CONTACTS:
                return context.getString(R.string.permission_write_contacts);
            case Manifest.permission.GET_ACCOUNTS:
                return context.getString(R.string.permission_get_accounts);
            case Manifest.permission.READ_CONTACTS:
                return context.getString(R.string.permission_read_contacts);
            case Manifest.permission.READ_CALL_LOG:
                return context.getString(R.string.permission_read_call_log);
            case Manifest.permission.READ_PHONE_STATE:
                return context.getString(R.string.permission_read_phone_state);
            case Manifest.permission.CALL_PHONE:
                return context.getString(R.string.permission_call_phone);
            case Manifest.permission.WRITE_CALL_LOG:
                return context.getString(R.string.permission_write_call_log);
            case Manifest.permission.USE_SIP:
                return context.getString(R.string.permission_use_sip);
            case Manifest.permission.PROCESS_OUTGOING_CALLS:
                return context.getString(R.string.permission_process_outgoing_calls);
            case Manifest.permission.ADD_VOICEMAIL:
                return context.getString(R.string.permission_add_voicemail);
            case Manifest.permission.READ_CALENDAR:
                return context.getString(R.string.permission_read_calendar);
            case Manifest.permission.WRITE_CALENDAR:
                return context.getString(R.string.permission_write_calendar);
            case Manifest.permission.CAMERA:
                return context.getString(R.string.permission_camera);
            case Manifest.permission.BODY_SENSORS:
                return context.getString(R.string.permission_body_sensors);
            case Manifest.permission.ACCESS_FINE_LOCATION:
                return context.getString(R.string.permission_access_fine_location);
            case Manifest.permission.ACCESS_COARSE_LOCATION:
                return context.getString(R.string.permission_access_coarse_location);
            case Manifest.permission.READ_EXTERNAL_STORAGE:
                return context.getString(R.string.permission_read_external_storage);
            case Manifest.permission.WRITE_EXTERNAL_STORAGE:
                return context.getString(R.string.permission_write_external_storage);
            case Manifest.permission.RECORD_AUDIO:
                return context.getString(R.string.permission_record_audio);
            case Manifest.permission.READ_SMS:
                return context.getString(R.string.permission_read_sms);
            case Manifest.permission.RECEIVE_WAP_PUSH:
                return context.getString(R.string.permission_receive_wap_push);
            case Manifest.permission.RECEIVE_MMS:
                return context.getString(R.string.permission_receive_mms);
            case Manifest.permission.RECEIVE_SMS:
                return context.getString(R.string.permission_receive_sms);
            case Manifest.permission.SEND_SMS:
                return context.getString(R.string.permission_send_sms);
            case "android.permission.READ_CELL_BROADCASTS":
                return context.getString(R.string.permission_read_cell_broadcasts);
        }
        return permission;
    }

    public static String permissionGroupName(Context context, String permission_group) {
        switch (permission_group) {
            case Manifest.permission_group.CALENDAR:
                return context.getString(R.string.permission_calendar);
            case Manifest.permission_group.CAMERA:
                return context.getString(R.string.permission_camera);
            case Manifest.permission_group.CONTACTS:
                return context.getString(R.string.permission_contacts);
            case Manifest.permission_group.LOCATION:
                return context.getString(R.string.permission_location);
            case Manifest.permission_group.MICROPHONE:
                return context.getString(R.string.permission_microphone);
            case Manifest.permission_group.PHONE:
                return context.getString(R.string.permission_phone);
            case Manifest.permission_group.SENSORS:
                return context.getString(R.string.permission_sensors);
            case Manifest.permission_group.SMS:
                return context.getString(R.string.permission_sms);
            case Manifest.permission_group.STORAGE:
                return context.getString(R.string.permission_storage);
        }
        return permission_group;
    }


    /**
     * checkSelfPermission
     *
     * @param handler    PermissionListener
     * @param permission {@link android.Manifest.permission}
     * @param name       权限名字
     * @param runnable   要运行的
     */
    private static void checkSelfPermission(PermissionHandler handler, String permission, String name, boolean noCallback, Runnable runnable) {
        Activity activity = handler.getActivity();
        if (activity == null) return;

        if (ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
            if (!ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
                final int requestCode = getRequestCode();
                handler.add(new PermissionItem(activity, permission, name, noCallback ? null : runnable, requestCode));
                handler.handlerRequestPermissions(new String[]{permission}, requestCode);
            } else {
                openPermissionDialog(activity, name);
            }
        } else runnable.run();
    }

    private static void checkSelfPermissions(PermissionHandler handler, String[] permissions, String[] name, boolean noCallback, Runnable runnable) {
        Activity activity = handler.getActivity();
        if (activity == null) return;
        ArrayList<String> array = new ArrayList<>();
        ArrayList<String> arrayName = new ArrayList<>();
        int i = 0;
        boolean shouldShowRequestPermissionRationale = false;
        for (String permission : permissions) {
            if (check(activity, permission)) {
                if (!shouldShowRequestPermissionRationale) {
                    shouldShowRequestPermissionRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
                }
                array.add(permission);
                arrayName.add(name[i]);
            }
            i++;
        }
        if (array.isEmpty()) runnable.run();
        else {
            if (shouldShowRequestPermissionRationale) {
                openPermissionDialog(activity, arrayName.toArray(new String[]{}));
                return;
            }
            int requestCode = getRequestCode();
            permissions = array.toArray(new String[]{});
            name = arrayName.toArray(new String[]{});
            handler.add(new PermissionItem(activity, permissions, name, noCallback ? null : runnable, requestCode));
            handler.handlerRequestPermissions(permissions, requestCode);
        }
    }

    private static boolean check(Context context, String permission) {
        return ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED;
    }

    private static int getRequestCode() {
        return Math.abs((int) System.currentTimeMillis() / 1000 % 10000);
    }

    public static void permissionRequest(int requestCode, String[] permissions, int[] grantResults, List<PermissionItem> permissionUtils) {
        if (permissionUtils == null || permissionUtils.isEmpty()) return;
        for (PermissionItem pu : permissionUtils) {
            if (requestCode == pu.requestCode) {
                pu.requestCode = -1;
                int count = grantResults.length;
                ArrayList<String> unGrantArray = null;
                for (int i = 0; i < count; i++) {
                    if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                        if (unGrantArray == null) unGrantArray = new ArrayList<>();
                        unGrantArray.add(pu.mPermissions.get(permissions[i]));
                    }
                }
                if (unGrantArray != null) {
                    openPermissionDialog(pu.activity, unGrantArray.toArray(new String[]{}));
                } else {
                    if (pu.runnable != null) pu.runnable.run();
                }
                permissionUtils.remove(pu);
                return;
            }
        }
    }

    private static void openPermissionDialog(final Context context, String... names) {
        showOpenPermissionDialog(context, context.getString(R.string.permission_notice, getNames(names)));
    }

    private static void showOpenPermissionDialog(final Context context, String message) {
        new AlertDialog.Builder(context)
                .setTitle("提示")
                .setMessage(message)
                .setCancelable(false)
                .setNeutralButton("拒绝", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                })
                .setNegativeButton("设置", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        openPermissionUI(context);
                        dialog.cancel();
                    }
                })
                .create()
                .show();
    }

    private static void openPermissionUI(Context context) {
        gotoMiui8Permission(context);
    }

    private static void gotoMiui8Permission(Context context) {
        Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR");
        localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
        localIntent.putExtra("extra_pkgname", getPackageName(context));
        try {
            context.startActivity(localIntent);
        } catch (Exception e) {
            e.printStackTrace();
            gotoMiuiPermission(context);
        }
    }

    /**
     * 跳转到miui的权限管理页面
     */
    private static void gotoMiuiPermission(Context context) {
        Intent i = new Intent("miui.intent.action.APP_PERM_EDITOR");
        ComponentName componentName = new ComponentName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
        i.setComponent(componentName);
        i.putExtra("extra_pkgname", getPackageName(context));
        try {
            context.startActivity(i);
        } catch (Exception e) {
            e.printStackTrace();
            gotoMeizuPermission(context);
        }
    }

    /**
     * 跳转到魅族的权限管理系统
     */
    private static void gotoMeizuPermission(Context context) {
        Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC");
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.putExtra("packageName", BuildConfig.APPLICATION_ID);
        try {
            context.startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
            gotoHuaweiPermission(context);
        }
    }

    /**
     * 华为的权限管理页面
     */
    private static void gotoHuaweiPermission(Context context) {
        try {
            Intent intent = new Intent();
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity");//华为权限管理
            intent.setComponent(comp);
            context.startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
            gotoAndroidPermission(context);
        }

    }

    private static void gotoAndroidPermission(Context context) {
        try {
            context.startActivity(getAppDetailSettingIntent(context));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取应用详情页面intent
     */
    private static Intent getAppDetailSettingIntent(Context context) {
        Intent localIntent = new Intent();
        localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        localIntent.setAction("android.settings.APhandlerICATION_DETAILS_SETTINGS");
        localIntent.setData(Uri.fromParts("package", getPackageName(context), null));

        /*if (Build.VERSION.SDK_INT >= 9) {
            localIntent.setAction("android.settings.APhandlerICATION_DETAILS_SETTINGS");
            localIntent.setData(Uri.fromParts("package", getPackageName(context), null));
        } else if (Build.VERSION.SDK_INT <= 8) {
            localIntent.setAction(Intent.ACTION_VIEW);
            localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
            localIntent.putExtra("com.android.settings.AphandlericationPkgName", getPackageName(context));
        }*/
        return localIntent;
    }

    private static String getPackageName(Context context) {
        return context.getPackageName();
    }
}
